package me.chyxion.spring.ext;

import java.util.Date;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.ParseException;
import java.beans.PropertyEditorSupport;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.ModelAndView;
import me.chyxion.spring.ext.exeptions.ExceptionResolver;
import me.chyxion.spring.ext.view.DefaultViewResolver.JSONView;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;

/**
 * @version 0.0.3
 * @since 0.0.1
 * @author Shaun Chyxion <br />
 * chyxion@163.com <br />
 * Jul 18, 2014 8:50:17 AM
 */
@Order(Ordered.LOWEST_PRECEDENCE)
@ControllerAdvice(annotations = {Controller.class, RestController.class})
public class BaseControllerAdvice {
    private static final Logger log = 
    	LoggerFactory.getLogger(BaseControllerAdvice.class);
	@Autowired
	private List<ExceptionResolver> exceptionResolvers;

	@ExceptionHandler(Throwable.class)
	public ModelAndView handleThrowable(Throwable ex) {
		if (log.isInfoEnabled()) {
			log.info("Exception [{}] [{}] Caused.", ex.getClass(), ex.getMessage());
		}
		// code, message
	    DataModel model = new DataModel(ex).setSuccess(false);
	    // custom exception resolvers
	    for (ExceptionResolver er : exceptionResolvers) {
	    	if (log.isDebugEnabled()) {
	    		log.debug("Exception Resolver [{}] Found.", er.getClass());
	    	}
	    	if (er.accept(ex)) {
	    		if (log.isDebugEnabled()) {
	    			log.info("Exception Has Been Accepted.");
	    		}
	    		model = er.process(model);
	    	}
	    }
	    return new ModelAndView(new JSONView(model));
	}

	@InitBinder
	public void registerCustomEditors(WebDataBinder binder, WebRequest request) {
		// register Date
		binder.registerCustomEditor(Date.class, new PropertyEditorSupport() {
			@Override
			public void setAsText(String text) {
				if (StringUtils.isNotBlank(text)) {
					if (text.matches("^\\d+$")) {
						setValue(Long.parseLong(text));
					}
					else {
						try {
							setValue(DateUtils.parseDate(text, 
								"yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss"));
						}
						catch (ParseException e) {
							log.warn("Could Not Parse Date [{}].", text);
						}
					}
				}
			}
		});
		// register JSONObject
		binder.registerCustomEditor(JSONObject.class, new PropertyEditorSupport() {
			@Override
			public void setAsText(String text) {
				if (StringUtils.isNotBlank(text)) {
					setValue(JSON.parseObject(text));
				}
			}
		});
		// register JSONArray
		binder.registerCustomEditor(JSONArray.class, new PropertyEditorSupport() {
			@Override
			public void setAsText(String text) {
				if (StringUtils.isNotBlank(text)) {
					setValue(JSON.parseArray(text));
				}
			}
		});
	}
}
